import shutil
import traceback
import re
import sys
import time
import struct


import chardet
import  binascii
from language import get_locale_text as _
from define import *
from my_api import *
import encrypt
import hashlib



class CheckScript():
    def __init__(self, logger):
        self.common_script_list = [
            "coroutine.lua", "string.lua", "table.lua", "math.lua", "io.lua", "os.lua", "bit.lua", "cpu.lua",
            "disp.lua", "i2c.lua", "pack.lua", "pio.lua", "pmd.lua", "rtos.lua", "uart.lua", "adc.lua", "iconv.lua",
            "audiocore.lua", "zlib.lua", "crypto.lua", "json.lua", "coroutine.lua", "table.lua", "debug.lua", "package.lua",
            "tcpipsock.lua", "watchdog.lua", "qrencode.lua", "zip.lua", "protobuf.c.lua"
        ]
        self.core_script_list = None
        self.ec616_script_list = [
            "httpcore.lua", "mqttcore.lua", "lpmem.lua", "nbiot.lua", "log.lua"
        ]
        self.logger = logger
        # 清洁过的lua文件列表
        self.temp_script_list = []
        # 资源文件路径列表
        self.resource_list = []
        # port文件路径
        self.port_file = None
        # 需要加载的lua模块列表
        self.require_module_list = []
        self.require_module_dict = {}
        self.PROJECT = ""
        self.VERSION = ""
        # sys.setrecursionlimit(1000000)
        self.temp_script_path = Path(os.getcwd(), TEMP_PATH, "script", "temp_script", "none")
        self.zip_script_path = Path(os.getcwd(), TEMP_PATH, "script", "zip_script", "none")
        self.encrypt_script_path = Path(os.getcwd(), TEMP_PATH, "script", "encrypt_script", "none")
        self.compile_script_path = Path(os.getcwd(), TEMP_PATH, "script", "compile_script", "none")
        self.encrypt = encrypt.Encrypt(self.encrypt_script_path.parent, self.logger)
        self.zip_exe_path = str(Path(WIN32_FILE_PATH, "7lzma.exe"))
        self.complie_exe_path = str(Path(WIN32_FILE_PATH, "luac.exe"))
        self.complie_float_exe_path = str(Path(WIN32_FILE_PATH, "luac_float.exe"))
        self.no_lib_flag = False
        self.require_head_list = [
            b'require',
            b'pcall(require,',
            b'dofile',
            b'load'
        ]
        self.all_file_crc_name = ".airm2m_all_crc#.bin"

    def del_old_temp_file(self):
        try:
            if os.path.exists(self.temp_script_path.parent):
                shutil.rmtree(self.temp_script_path.parent)
            os.makedirs(self.temp_script_path.parent)
            # 清洁过的lua文件列表
            self.temp_script_list = []
            # 资源文件路径列表
            self.resource_list = []
            # port文件路径
            self.port_file = None
            # 需要加载的lua模块列表
            self.require_module_list = []
            self.require_module_dict = {}
            self.PROJECT = ""
            self.VERSION = ""
            self.no_lib_flag = False
            return True, None
        except Exception as e:
            return False, str(self.temp_script_path.parent) + " " + _("被占用") + " " + _("请查看是否使用管理员权限打开")

    def __find_block(self, org_data):
        pos = 0
        cnt = 0
        data_len = len(org_data)
        quotes_1_index = None   # ''
        quotes_2_index = None   # ""
        block_1_index = None    # [[]]
        block_2_index = None    # [====[]====]
        min_index = None
        next_index = -1
        start_index = None
        end_index = None
        if org_data[0] == 0x5c:
            pos = 1
        while pos < data_len:
            start_index = org_data.find(b"--", pos)
            quotes_1_index = org_data.find(b"\'", pos)
            quotes_2_index = org_data.find(b"\"", pos)
            block_1_index = org_data.find(b"[[", pos)
            block_2_index = org_data.find(b"[====[", pos)
            if start_index == -1:
                break
            if quotes_1_index == -1:
                quotes_1_index = 0xffffffff
            if quotes_2_index == -1:
                quotes_2_index = 0xffffffff
            if block_1_index == -1:
                block_1_index = 0xffffffff
            if block_2_index == -1:
                block_2_index = 0xffffffff
            min_index = min(start_index, quotes_1_index, quotes_2_index, block_1_index, block_2_index)
            # min_index = min(start_index, quotes_1_index, quotes_2_index, block_1_index)
            if start_index == min_index:
                pos = start_index
                if (pos+4) <= data_len and org_data[pos:pos+4] == b"--[[":
                    next_index = org_data.find(b"]]", pos)
                    if next_index != -1:
                        start_index = pos
                        pos = next_index + 2
                    else:
                        return False, "[[]]" + _("不配对")
                elif (pos+8) <= data_len and org_data[pos:pos+8] == b"--[====[":
                    next_index = org_data.find(b"]====]", pos)
                    if next_index != -1:
                        start_index = pos
                        pos = next_index + 6
                    else:
                        return False, "[====[]====]" + _("不配对")
                else:
                    next_index = org_data.find(b"\n", pos)
                    if next_index != -1:
                        start_index = pos
                        pos = next_index + 1
                    else:
                        start_index = pos
                        pos = data_len
                # start_time = time.time()
                for j in range(start_index, pos):
                    if org_data[j] != 0x0a:
                        org_data[j] = 0x20
                # print(time.time() - start_time)
            elif quotes_1_index == min_index:
                if org_data[quotes_1_index - 1] == 0x5c:
                    pos = quotes_1_index + 1
                else:
                    pos = quotes_1_index + 1
                    while pos < data_len:
                        next_index = org_data.find(b"\'", pos)
                        if next_index != -1:
                            if org_data[next_index-1] == 0x5c:  # 排除转义
                                pos = next_index + 1
                            else:
                                # self.logger.info("{} {} {} {}".format(quotes_1_index, org_data[quotes_1_index], next_index, org_data[next_index]))
                                pos = next_index + 1
                                break
                        else:
                            return False, _("单引号不配对")
            elif quotes_2_index == min_index:
                if org_data[quotes_2_index - 1] == 0x5c:
                    pos = quotes_2_index + 1
                else:
                    pos = quotes_2_index + 1
                    while pos < data_len:
                        next_index = org_data.find(b"\"", pos)
                        if next_index != -1:
                            if org_data[next_index-1] == 0x5c:  # 排除转义
                                pos = next_index + 1
                            else:
                                # self.logger.info("{} {} {} {}".format(quotes_2_index, org_data[quotes_2_index], next_index, org_data[next_index]))
                                pos = next_index + 1
                                break
                        else:
                            return False, _("双引号不配对")
            elif block_1_index == min_index:
                pos = block_1_index
                next_index = org_data.find(b"]]", pos)
                if next_index != -1:
                    # self.logger.info("{} {} {} {}".format(block_1_index, org_data[block_1_index:block_1_index+2], next_index, org_data[next_index:next_index+2]))
                    pos = next_index + 2
                else:
                    return False, "[[]]" + _("不配对")
            elif block_2_index == min_index:   # [====[
                next_index = org_data.find(b"]====]", pos)
                if next_index != -1:
                    # self.logger.info("{} {} {} {}".format(block_2_index, org_data[block_2_index:block_2_index+6], next_index, org_data[next_index:next_index+6]))
                    pos = next_index + 6
                else:
                    return False, "[====[]====]" + _("不配对")
            else:
                pass

        return True, None

    def __clean(self, org_data):
        module_list = []
        result, error = self.__find_block(org_data)
        if not result:
            return result, error, []
        _line_list = org_data.splitlines(False)
        _line = None
        new_data = bytearray()
        for i in range(0, len(_line_list)):
            new_data.extend(_line_list[i].strip())
            new_data.append(0x0a)
        # 搜索所有require
        model1 = re.compile(rb"\s*[\'\"](.+)[\'\"]")
        model2 = re.compile(rb"\s*\([\'\"](.+)[\'\"]\)")
        hex_dig = [x for x in range(48, 58)] + [x for x in range(65, 91)] + [x for x in range(97, 123)] + [95]
        # start = b"require"
        # index = new_data.find(start)
        # while index != -1:
        #     mm = re.match(model1, new_data[index+7:])
        #     if mm:
        #         module_list.append(decode_ch(mm.group(1)) + '.lua')
        #     else:
        #         mm = re.match(model2, new_data[index+7:])
        #         if mm:
        #             module_list.append(decode_ch(mm.group(1)) + '.lua')
        #     index = new_data.find(start, index+7)
        # start = b"pcall(require,"
        # index = new_data.find(start)
        # while index != -1:
        #     mm = re.match(model1, new_data[index+14:])
        #     if mm:
        #         module_list.append(decode_ch(mm.group(1)) + '.lua')
        #     else:
        #         mm = re.match(model2, new_data[index+14:])
        #         if mm:
        #             module_list.append(decode_ch(mm.group(1)) + '.lua')
        #     index = new_data.find(start, index+14)
        for start in self.require_head_list:
            index = new_data.find(start)
            while index != -1:
                t = int.from_bytes(new_data[index - 1:index], byteorder='little', signed=False)
                if index == 0 or int.from_bytes(new_data[index - 1:index], byteorder='little', signed=False) not in hex_dig:
                    mm = re.match(model1, new_data[index+len(start):])
                    if mm:
                        lua_name = os.path.basename(mm.group(1))
                        if lua_name.find(b'.lua') != -1:
                            lua_name = os.path.basename(decode_ch(lua_name))
                            module_list.append(lua_name)
                            print(lua_name)
                        else:
                            module_list.append(decode_ch(lua_name) + '.lua')
                    else:
                        mm = re.match(model2, new_data[index+len(start):])
                        if mm:
                            lua_name = os.path.basename(mm.group(1))
                            if lua_name.find(b'.lua') != -1:
                                lua_name = os.path.basename(decode_ch(lua_name))
                                module_list.append(lua_name)
                                print(lua_name)
                            else:
                                module_list.append(decode_ch(lua_name) + '.lua')
                index = new_data.find(start, index+len(start))
        return True, new_data, module_list

    def __get_soft_ver(self, main_context):
        project = main_context.find(b"PROJECT")
        version = main_context.find(b"VERSION")
        if project != -1 and version != -1:
            k = re.match(b".+[\'\"](.+)[\'\"].*\n", main_context[project:])
            j = re.match(b".+[\'\"](.+)[\'\"].*\n", main_context[version:])

            if k and j:
                self.PROJECT = decode_ch(k.group(1))
                self.VERSION = decode_ch(j.group(1))
                return True, None
            else:
                return False, _("main.lua的PROJECT或者VERSION,没有定义")
        else:
            return False, _("main.lua缺少PROJECT或者VERSION")

    def clean_file(self,  file_list, add_core_script_list=[]):
        all_text_data = b""
        require_module_list = []
        
        self.core_script_list = self.common_script_list + add_core_script_list
        for _file in file_list:
            if not _file.isascii():
                return False, _("文件") + " " + str(_file.with_name(_file)) + " " + _("文件名称有中文")
            name = os.path.basename(_file)
            base_name, suffix = os.path.splitext(_file)
            if suffix == ".lua":
                with open(_file, 'rb') as f:
                    all_text_data = f.read()
                if all_text_data:
                    if _file.find("config.lua") != -1:
                        pass
                    else:
                        all_text_data = bytearray(all_text_data.replace(b"\r\n", b"\n"))
                        result, all_text_data, require_module_list = self.__clean(all_text_data)
                        if not result:
                            return result, _("文件") + " " + str(_file) + " " + all_text_data
                    if name == 'main.lua':
                        result, error = self.__get_soft_ver(all_text_data)
                        if not result:
                            return result, error
                        # self.logger.info(self.VERSION + " " + self.PROJECT)
                try:
                    ss = self.temp_script_path.with_name(name)
                    with open(self.temp_script_path.with_name(name), 'wb') as f:
                        f.write(all_text_data)
                except Exception as Error:
                    return False, str(self.temp_script_path.parent) + " " + _("被占用") + " " + _("请查看是否使用管理员权限打开")
                self.temp_script_list.append(name)
                # print(base_name, "require", require_module_list)
                self.require_module_dict[name] = require_module_list
            else:
                self.resource_list.append(_file)
        return True, None

# 检查文件依赖关系和是否缺失
    def check_file_depends(self):
        result = True
        error = None
        if 'main.lua' not in self.require_module_dict:
            return False, _("缺少") + " " + "main.lua" + " " + _("请添加")
        if 'sys.lua' not in self.require_module_dict:
            self.no_lib_flag = True
        next_check_list = ['main.lua']
        self.require_module_list = ['main.lua']
        already_check_list = []
        while next_check_list:
            check_list = []
            for check in next_check_list:
                if check in self.core_script_list:
                    continue
                already_check_list.append(check)
                if check not in self.require_module_list:
                    if check not in self.temp_script_list:
                        return False, _("缺少") + " " + check + " " + _("请添加")
                    self.require_module_list.append(check)
                for new_check in self.require_module_dict[check]:
                    if new_check not in check_list:
                        check_list.append(new_check)
                # check_list = check_list + self.require_module_dict[check]
            for del_check in already_check_list:
                if del_check in check_list:
                    check_list.remove(del_check)
            next_check_list = check_list
        for check in self.temp_script_list:
            if check not in self.require_module_list:
                try:
                    os.remove(self.temp_script_path.with_name(check))
                except Exception as e:
                    return False, _("无法删除") + " " + check + " "
        return result, error

    def add_trace_file(self, port):
        head = struct.pack("<BBB", 0xEF, 0xBB, 0xBF) + ("\r\n[trace]\r\r\nport = {}\r\n\r\n".format(port)).encode("utf-8")
        with open(self.temp_script_path.with_name("amcfg.ini"), 'wb') as f:
            f.write(head)
        self.port_file = self.temp_script_path.with_name("amcfg.ini")

    def merge_add_head(self):
        if self.port_file:
            add_1 = 1
        else:
            add_1 = 0
        self.bin_data = bytearray()
        magic_mag = struct.pack("<BBI", 0x01, 0x04, 0xA55AA55A)
        version_mag = struct.pack("<BBh", 0x02, 0x02, 0x2)
        length_msg = struct.pack("<BBI", 0x03, 0x04, 0x18)
        file_num_msg = struct.pack("<BBH", 0x04, 0x02, len(self.require_module_list) + len(self.resource_list) + add_1 + 1)
        crc_head = struct.pack("<BB", 0xFE, 0x02)
        data = magic_mag + version_mag + length_msg + file_num_msg + crc_head
        self.bin_data.extend(data)
        num = sum_check(data)
        self.bin_data.extend(struct.pack("<H", num))

        if self.port_file:
            self.merge_add_body(str(self.port_file))
        

    def merge_add_body(self, dir_path, file_name=None):                 # 添加头文件的单个文件
        if not file_name:
            file_name = os.path.basename(dir_path)
            dir_path = os.path.dirname(dir_path)
        # if not file_name.isascii():
        #     return False
        # self.logger.info("add {}".format(str(Path(dir_path, file_name))))
        magic_mag = struct.pack("<BBI", 0x01, 0x04, 0xA55AA55A)
        n = len(file_name)
        name_msg = struct.pack("<BB%is" % n, 0x02, n, encode_ch(file_name, d='utf-8'))
        try:
            with open(Path(dir_path, file_name), "rb") as f:
                file_data = f.read()
        except Exception as identifier:
            self.logger.error('\r\n{}'.format(traceback.format_exc()))
            return False
        length_msg = struct.pack("<BBI", 0x03, 0x04, len(file_data))
        crc_head = struct.pack("<BB", 0xFE, 0x02)
        data = magic_mag + name_msg + length_msg + crc_head
        self.bin_data.extend(data)
        num = sum_check(data)
        self.bin_data.extend(struct.pack("<H", num))
        self.bin_data.extend(file_data)
        return True

    def merge_add_all_crc(self):                 # 添加全文件CRC 校验
        magic_mag = struct.pack("<BBI", 0x01, 0x04, 0xA55AA55A)
        n = len(self.all_file_crc_name)
        name_msg = struct.pack("<BB%is" % n, 0x02, n, encode_ch(self.all_file_crc_name, d='utf-8') )

        length_msg = struct.pack("<BBI", 0x03, 0x04, 16)
        crc_head = struct.pack("<BB", 0xFE, 0x02)
        data = magic_mag + name_msg + length_msg + crc_head
        self.bin_data.extend(data)
        num = sum_check(data)

        self.bin_data.extend(struct.pack("<H", num))
        soft_md5  =   hashlib.md5(self.bin_data).hexdigest()
        if len(soft_md5) != 32:
            raise  Exception("md5 check err %d"%len(soft_md5))
        print(len(self.bin_data),soft_md5)

        self.bin_data.extend(binascii.a2b_hex(soft_md5))

        return True

    def zip_file_list(self, dir_path, file_name=None):
        if not file_name:
            file_name = os.path.basename(dir_path)
            dir_path = os.path.dirname(dir_path)
        input_path = str(Path(dir_path, file_name))
        file_name_base, suffix = os.path.splitext(file_name)
        if suffix != '.zip':
            cmd = self.zip_exe_path + " e" + " \"" + input_path + "\" \"" + str(self.zip_script_path.with_name(file_name + ".zip")) + "\""
            # cmd = self.zip_exe_path + ' a ' + "\"" + str(self.zip_script_path.with_name(file_name_base + ".zip")) + "\"" + " \"" + input_path + "\""
            error = run_cmd(cmd, self.logger, True, self.zip_exe_path)
            if error:
                return False, error
            else:
                return True, None
        else:
            shutil.copy(input_path, self.zip_script_path.with_name(file_name))
            return True, None

    def __merge_zip_encrypt_file(self):
        if os.path.exists(self.zip_script_path.parent):
            shutil.rmtree(self.zip_script_path.parent)
        os.makedirs(self.zip_script_path.parent)
        for _file in self.require_module_list:
            result, error = self.zip_file_list(self.encrypt_script_path.parent, _file + 'e')
            if not result:
                return result, _("压缩加密脚本") + " " + str(_file) + " " + _("出现错误：") + error
        for _file in self.resource_list:
            result, error = self.zip_file_list(_file)
            if not result:
                return result, _("压缩资源文件") + " " + str(_file) + " " + _("出现错误：") + error
        file_list = get_file_from_path(self.zip_script_path.parent, 'zip')
        if not file_list:
            return False, _("压缩文件失败")

        self.merge_add_head()
        for _file in file_list:
            if not self.merge_add_body(self.zip_script_path.parent, _file):
                return False, _("合并") + " " + str(_file) + " " + _("时发生错误")
        return True, self.bin_data

    def __merge_zip_file(self):
        if os.path.exists(self.zip_script_path.parent):
            shutil.rmtree(self.zip_script_path.parent)
        os.makedirs(self.zip_script_path.parent)
        for _file in self.require_module_list:
            result, error = self.zip_file_list(self.temp_script_path.parent, _file)
            if not result:
                return result, _("压缩脚本") + " " + str(_file) + " " + _("出现错误：") + error
        for _file in self.resource_list:
            result, error = self.zip_file_list(_file)
            if not result:
                return result, _("压缩资源文件") + " " + str(_file) + " " + _("出现错误：") + error
        file_list = get_file_from_path(self.zip_script_path.parent, 'zip')
        if not file_list:
            return False, _("压缩文件失败")

        self.merge_add_head()
        for _file in file_list:
            if not self.merge_add_body(self.zip_script_path.parent, _file):
                return False, _("合并") + " " + str(_file) + " " + _("时发生错误")
        return True, self.bin_data

    def merge_script(self, lua_space_len, force_compile=False, zip_enable=False, force_zip=False, encrypt_code=None, is_float=False, is_debug=False):
        if force_compile:
            try:
                if os.path.exists(self.compile_script_path.parent):
                    shutil.rmtree(self.compile_script_path.parent)
                os.makedirs(self.compile_script_path.parent)
                if is_float:
                    for _file in self.require_module_list:
                        if _file == 'main.lua':
                            cmd = "{0} -o \"{2}\" \"{1}\"".format(self.complie_float_exe_path, str(self.temp_script_path.with_name(_file)), str(self.compile_script_path.with_name(_file)) + "c")
                        else:
                            if is_debug:
                                cmd = "{0} -o \"{2}\" \"{1}\"".format(self.complie_float_exe_path, str(self.temp_script_path.with_name(_file)), str(self.compile_script_path.with_name(_file)) + "c")
                            else:
                                cmd = "{0} -s -o \"{2}\" \"{1}\"".format(self.complie_float_exe_path, str(self.temp_script_path.with_name(_file)), str(self.compile_script_path.with_name(_file)) + "c")
                        error = run_cmd(cmd, self.logger, True, self.complie_float_exe_path)
                        if error:
                            return False, error
                else:
                    for _file in self.require_module_list:
                        if _file == 'main.lua':
                            cmd = "{0} -o \"{2}\" \"{1}\"".format(self.complie_exe_path, str(self.temp_script_path.with_name(_file)), str(self.compile_script_path.with_name(_file)) + "c")
                        else:
                            if is_debug:
                                cmd = "{0} -o \"{2}\" \"{1}\"".format(self.complie_exe_path, str(self.temp_script_path.with_name(_file)), str(self.compile_script_path.with_name(_file)) + "c")
                            else:
                                cmd = "{0} -s -o \"{2}\" \"{1}\"".format(self.complie_exe_path, str(self.temp_script_path.with_name(_file)), str(self.compile_script_path.with_name(_file)) + "c")
                        error = run_cmd(cmd, self.logger, True, self.complie_exe_path)
                        if error:
                            return False, error
                self.merge_add_head()
                file_list = get_file_from_path(self.compile_script_path.parent, '.luac')
                for _file in file_list:
                    if not self.merge_add_body(self.compile_script_path.parent, _file):
                        return False, _file[0:-1] + " " + _("合并时发生错误")
                for _file in self.resource_list:
                    if not self.merge_add_body(_file):
                        return False, _("合并") + " " + str(_file) + " " + _("时发生错误")
                if len(self.bin_data) > lua_space_len:
                    self.logger.info("合并后文件过大，尝试压缩合并")
                    self.merge_add_head()
                    file_list = get_file_from_path(self.compile_script_path.parent, 'luac')
                    for _file in file_list:
                        if not self.merge_add_body(self.compile_script_path.parent, _file):
                            return False, _file[0:-1] + " " + _("合并时发生错误")
                    for _file in self.resource_list:
                        result, error = self.zip_file_list(_file)
                        if not result:
                            return result, _("压缩资源文件") + " " + str(_file) + " " + _("出现错误：") + error
                    file_list = get_file_from_path(self.zip_script_path.parent, 'zip')
                    if not file_list:
                        return False, _("压缩文件失败")
                    for _file in file_list:
                        if not self.merge_add_body(self.zip_script_path.parent, _file):
                            return False, _("合并") + " " + str(_file) + " " + _("时发生错误")
                    if len(self.bin_data) > lua_space_len:
                        return False, _("加密合并压缩后超出了底层文件能支持的空间，请更换底层文件，或者修改脚本、资源文件")
                    else:
                        self.merge_add_all_crc()
                        return True, self.bin_data
            except Exception as e:
                self.logger.error("\r\n{}".format(traceback.format_exc()))
                return False, _("检测异常")
            self.merge_add_all_crc()
            return True, self.bin_data

        if encrypt_code:
            encrypt_code = encode_ch(encrypt_code)
            if len(encrypt_code) > 16:
                return False, _("秘钥长度超过16字节")
            if not self.encrypt.encrypt_file_list(encrypt_code, self.temp_script_path.parent, self.require_module_list):
                return False, _("加密脚本发生错误")
            if force_zip:
                result, self.bin_data = self.__merge_zip_encrypt_file()
                if not result:
                    return result, self.bin_data
                if len(self.bin_data) > lua_space_len:
                    return False, _("加密合并压缩后超出了底层文件能支持的空间，请更换底层文件，或者修改脚本、资源文件")
                else:
                    self.merge_add_all_crc()
                    return True, self.bin_data
            else:
                self.merge_add_head()
                file_list = get_file_from_path(self.encrypt_script_path.parent, "luae")
                if not file_list:
                    return False, _("加密脚本失败")
                for _file in file_list:
                    if not self.merge_add_body(self.encrypt_script_path.parent, _file):
                        return False, _file[0:-1] + " " + _("合并时发生错误")
                for _file in self.resource_list:
                    if not self.merge_add_body(_file):
                        return False, str(_file) + " " + _("合并时发生错误")
                if len(self.bin_data) > lua_space_len:
                    if zip_enable:
                        result, self.bin_data = self.__merge_zip_encrypt_file()
                        if not result:
                            return result, self.bin_data
                        if len(self.bin_data) > lua_space_len:
                            return False, _("加密合并压缩后超出了底层文件能支持的空间，请更换底层文件，或者修改脚本、资源文件")
                        else:
                            self.merge_add_all_crc()
                            return True, self.bin_data
                    return False, _("加密合并后超出了底层文件能支持的空间，请更换底层文件，或者修改脚本、资源文件")
                self.merge_add_all_crc()
                return True, self.bin_data
        else:
            if force_zip:
                result, self.bin_data = self.__merge_zip_file()
                if not result:
                    return result, self.bin_data
                if len(self.bin_data) > lua_space_len:
                    return False, _("压缩合并后超出了底层文件能支持的空间，请更换底层文件，或者修改脚本、资源文件")
                self.merge_add_all_crc()
                return True, self.bin_data
            else:
                self.merge_add_head()
                for _file in self.require_module_list:
                    if not self.merge_add_body(self.temp_script_path.parent, _file):
                        return False, _("合并") + " " + str(_file) + " " + _("时发生错误")
                for _file in self.resource_list:
                    if not self.merge_add_body(_file):
                        return False, _("合并") + " " + str(_file) + " " + _("时发生错误")
                if len(self.bin_data) > lua_space_len:
                    self.logger.info("合并后文件过大，尝试压缩合并")
                    if zip_enable:
                        result, self.bin_data = self.__merge_zip_file()
                        if not result:
                            return result, self.bin_data
                        if len(self.bin_data) > lua_space_len:
                            return False, _("压缩合并后超出了底层文件能支持的空间，请更换底层文件，或者修改脚本、资源文件")
                        self.merge_add_all_crc()
                        return True, self.bin_data
                    else:
                        return False, _("合并后超出了底层文件能支持的空间，请更换底层文件，或者修改脚本、资源文件")
                else:
                    self.merge_add_all_crc()
                    return True, self.bin_data

    def check_lua_grammar(self, dir, file_list, is_float=False):
        try:
            if os.path.exists(self.compile_script_path.parent):
                shutil.rmtree(self.compile_script_path.parent)
            os.makedirs(self.compile_script_path.parent)
            for _file in file_list:
                if os.path.splitext(_file)[1] == '.lua':
                    if is_float:
                        cmd = "{0} -s -o \"{2}\" \"{1}\"".format(self.complie_float_exe_path, str(Path(dir, _file)), str(self.compile_script_path.with_name(_file)) + "c")
                        error = run_cmd(cmd, self.logger, True, self.complie_float_exe_path)
                    else:
                        cmd = "{0} -s -o \"{2}\" \"{1}\"".format(self.complie_exe_path, str(Path(dir, _file)), str(self.compile_script_path.with_name(_file)) + "c")
                        error = run_cmd(cmd, self.logger, True, self.complie_exe_path)
                    if error:
                        return False, error
                else:
                    pass
        except Exception as e:
            self.logger.error("\r\n{}".format(traceback.format_exc()))
            return False, _("检测异常")
        return True, None
